package tools.NW3D;

import java.util.ArrayList;

import tools.kmer.KmerSet_binary;

public class Nw3d extends SequenceAlignment{

	private Cell highScoreCell;
	private KmerSet_binary kmers;
	private String initialKmer;
	final private char[] nucs= new char[] {'A','C','G','T'};
	
	private Nw3d(String sequence1, String sequence2){
		super(sequence1, sequence2);
	}
	
	private Nw3d(String sequence1, String sequence2, int match, int mismatch, int gap){
		super(sequence1,sequence2, match, mismatch,gap);
	}
	
	public Nw3d(String sequence, int match, int mismatch, int gap, KmerSet_binary kmers){
		super(sequence.substring(kmers.getKmerSize()),(sequence+sequence.substring(sequence.length()/2)).substring(kmers.getKmerSize()),match, mismatch, gap);
		this.kmers= kmers;
		this.initialKmer=sequence.substring(0, kmers.getKmerSize());
	}
	
	protected void initialize(){
		super.initialize();
		
		scoreTable[0][0].setKmer(initialKmer);
		highScoreCell= scoreTable[scoreTable.length-1][0];
	}
	
	
	//needs update to incorporate kmers
	protected void fillInCell(Cell currentCell, Cell cellAbove, Cell cellLeft, Cell cellAboveLeft){
		int rowSpaceScore= cellAbove.getScore()+space;//deletion
		int colSpaceScore= cellLeft.getScore() + space;//insert
		int matchOrMismatchScore= cellAboveLeft.getScore();//mismatch
		
		String prefix=cellAboveLeft.getKmer().substring(1);
		ArrayList<String> alts= new ArrayList<String>();
		String kmer;
		boolean found=false,hasAbove= (cellAbove.getKmer().length()>0),hasAboveLeft= (cellAboveLeft.getKmer().length()>0),hasLeft=(cellLeft.getKmer().length()>0);
		
		if(currentCell.getCol()>47){
			found=false;
		}
		for (char nuc : nucs) {
			if(kmers.existsND(kmer=prefix+nuc)){
				if(nuc==sequence1.charAt(currentCell.getRow() -1)){
					alts.add(0, kmer);
					found=true;
				}else{
					alts.add(kmer);
				}
			}
		}
		
		if(found){
			matchOrMismatchScore+=match;
			kmer=alts.remove(0);
		}else if(alts.size()>0){
			matchOrMismatchScore+=mismatch;
			kmer=alts.remove(0);
		}else{
			matchOrMismatchScore+=2*space; //assumes a negative cost for a space
			kmer=prefix+sequence1.charAt(currentCell.getRow() -1);
		}
		
		if(hasAbove && rowSpaceScore >= colSpaceScore){
			if(hasAboveLeft && matchOrMismatchScore >= rowSpaceScore){
				currentCell.setScore(matchOrMismatchScore);
				currentCell.setPrevCell(cellAboveLeft);
				currentCell.setAlternatives(alts);
				currentCell.setKmer(kmer);
				
			}else{
				currentCell.setScore(rowSpaceScore);
				currentCell.setPrevCell(cellAbove);
				currentCell.setAlternatives(cellAbove.getAlternatives());
				currentCell.setKmer(cellAbove.getKmer());
				
			}
		}else{
			if(hasAboveLeft && matchOrMismatchScore>=colSpaceScore){
				currentCell.setScore(matchOrMismatchScore);
				currentCell.setPrevCell(cellAboveLeft);
				currentCell.setAlternatives(alts);
				currentCell.setKmer(kmer);
			}else{
				currentCell.setScore(colSpaceScore);
				currentCell.setPrevCell(cellLeft);
				if(hasLeft){
					alts.clear();
					prefix= cellLeft.getKmer().substring(1);
					for (char nuc : nucs) {
						if(kmers.existsND(kmer=prefix+nuc)){
							if(nuc==sequence1.charAt(currentCell.getRow() -1)){
								alts.add(0, kmer);
							}else{
								alts.add(kmer);
							}
						}
					}
					if(alts.size()>0){
						kmer=alts.remove(0);
					}else{
						kmer=prefix+sequence1.charAt(currentCell.getRow() -1);
					}
					currentCell.setAlternatives(alts);
					currentCell.setKmer(kmer);
				}else{
					currentCell.clearAlternatives();
					currentCell.setKmer("");
				}
			}
		}
		if(currentCell.getScore() > highScoreCell.getScore() && currentCell.getRow()==scoreTable.length-1){
			highScoreCell = currentCell;
		}
	}

	public String correct(){
		int bestScore=this.getAlignmentScore();
		return "";
	}
	
	@Override
	protected Object getTraceback(){
		StringBuffer align1Buf= new StringBuffer();
		StringBuffer align2Buf= new StringBuffer();
		Cell currentCell= getTracebackStartingCell();
		while(traceBackIsNotDone(currentCell)){
			if(currentCell.getRow()-currentCell.getPrevCell().getRow()==1){
				align2Buf.insert(0, currentCell.getKmer().charAt(kmers.getKmerSize()-1));
			}else{
				align2Buf.insert(0, '-');
			}
			if(currentCell.getCol()-currentCell.getPrevCell().getCol()==1){
				align1Buf.insert(0, sequence1.charAt(currentCell.getCol()-1));
			}else{
				align1Buf.insert(0,'-');
			}
			currentCell=currentCell.getPrevCell();
		}
		String[] alignments= new String[] {align1Buf.toString(), align2Buf.toString()};
		
		return alignments;
	}
	
	@Override
	protected boolean traceBackIsNotDone(Cell currentCell){
		return currentCell.getPrevCell() != null;
	}
	
	
	@Override
	protected Cell getTracebackStartingCell(){
		return highScoreCell;
	}
	
	@Override
	public String toString(){
		return "[Nw3d: sequence1="+sequence1+". sequence2="+sequence2+"]";
	}
	
	protected Cell getInitialPointer(int row, int col){
		if(row ==0 && col!=0){
			return scoreTable[row][col-1];
		}else if(col ==0 && row!=0){
			return scoreTable[row-1][col];
		}else{
			return null;
		}
	}
	
	protected int getInitialScore(int row, int col){
		if(row==0 && col!=0){
			return col*space;
		}else if(col==0 && row !=0){
			return row*space;
		}else{
			return 0;
		}
	}
	
	protected String getInitialKmer(int row, int col){
		if(col==0||row==0){
			return initialKmer;
		}else{
			return "";
		}
	}
	
	
	
	
	
	
	
	
	
	
	
	
	
	
	
	
	
	
	
	
	
	
	
}
